package com.ejlchina.tool.fragment.offline

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
import android.location.LocationManager
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.adolf.androiddemo.R
import com.adolf.androiddemo.databinding.FragmentScanOfflineBinding
import com.ejlchina.tool.MainActivity
import com.ejlchina.tool.adapter.ScanDeviceAdapter
import com.ejlchina.tool.base.BaseBindingFragment2
import com.ejlchina.tool.bean.BleDeviceBean
import com.ejlchina.tool.callback.ReceiverCallback
import com.ejlchina.tool.constant.BLUETOOTH_NAME_OFFLINE
import com.ejlchina.tool.constant.BLUETOOTH_NAME_ONLINE
import com.ejlchina.tool.constant.COMMAND_DELAY_TIME_100
import com.ejlchina.tool.constant.COMMAND_DELAY_TIME_300
import com.ejlchina.tool.constant.DEVICE_MODE_NO_SELECT
import com.ejlchina.tool.constant.DEVICE_MODE_ONLINE
import com.ejlchina.tool.constant.OFFLINE_DEVICE_LEFT
import com.ejlchina.tool.constant.SP_DEVICE_MODE
import com.ejlchina.tool.enums.SuccessFailEnum
import com.ejlchina.tool.extension.safeNavigate
import com.ejlchina.tool.singleton.GlobalAction
import com.ejlchina.tool.singleton.GlobalConnectObject
import com.ejlchina.tool.singleton.GlobalParams
import com.ejlchina.tool.singleton.SharedPreferenceUtil
import com.ejlchina.tool.util.BleScan
import com.ejlchina.tool.util.COMMAND_FIRMWARE_VERSION_DOWNWARD
import com.ejlchina.tool.util.COMMAND_FIRMWARE_VERSION_UPWARD
import com.ejlchina.tool.util.COMMAND_TEMPERATURE_ALARM_GET_DOWNWARD
import com.ejlchina.tool.util.COMMAND_TEMPERATURE_ALARM_GET_UPWARD
import com.ejlchina.tool.util.COMMAND_TEMPERATURE_ALARM_SET_DOWNLOAD
import com.ejlchina.tool.util.COMMAND_TEMPERATURE_ALARM_SET_UPWARD
import com.ejlchina.tool.util.COMMAND_TEMPERATURE_GET_OFFLINE_DOWNWARD
import com.ejlchina.tool.util.COMMAND_TEMPERATURE_GET_OFFLINE_UPWARD
import com.ejlchina.tool.util.COMMAND_TOKEN_DOWNWARD
import com.ejlchina.tool.util.COMMAND_TOKEN_UPWARD
import com.ejlchina.tool.util.LOG_TAG
import com.ejlchina.tool.util.bytearray.intToByteHexString
import com.ejlchina.tool.util.bytearray.toHexString
import com.ejlchina.tool.util.getVersionNo
import com.ejlchina.tool.util.getVersionNoOffline
import com.ejlchina.tool.util.getVersionNumber
import com.ejlchina.tool.util.showToast
import com.ejlchina.tool.util.timestamp
import com.huyuhui.fastble.BleManager
import com.huyuhui.fastble.callback.BleRssiCallback
import com.huyuhui.fastble.data.BleDevice
import com.huyuhui.fastble.exception.BleException
import com.huyuhui.fastble.scan.BleScanRuleConfig
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlin.properties.Delegates


@SuppressLint("MissingPermission")
class ScanOfflineFragment: BaseBindingFragment2<FragmentScanOfflineBinding>(), ReceiverCallback {

    private val autoConnectFlow = MutableSharedFlow<Boolean>(0,1,BufferOverflow.SUSPEND)
    private val readToAutoConnectList = mutableListOf<BleDeviceBean>()
    private val scanFlow = IntRange(1,5).asFlow()
    private var scanJob: Job? = null
    private var isCanReceiveTemperatureAlarmInfo = false

    //启用蓝牙
    private val enableBluetooth = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            if (!isOpenLocation()){
                enableGPSLocation.launch(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
            }else {
                requestLocationPermissions.launch(
                    arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
                )
            }
        } else {
            showToast("蓝牙关闭")
        }
    }

    //蓝牙连接权限
    private val enableBluetoothConnect = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
        val resultScan = result[Manifest.permission.BLUETOOTH_SCAN]
        val resultConnect = result[Manifest.permission.BLUETOOTH_CONNECT]
        val resultAdvertise = result[Manifest.permission.BLUETOOTH_ADVERTISE]
        if (resultScan == true && resultConnect == true && resultAdvertise == true) {
            enableBluetooth.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))
        } else {
            showToast("连接权限被拒绝")
        }
    }

    private var isScanning :Boolean by Delegates.observable(false){_,_,newValue ->
        Log.i(LOG_TAG,"isScanning = $isScanning")
        if (isAdded) {
            binding.refreshLayout.isRefreshing = newValue
        }
        if (newValue) {
            deviceList.clear()
            addConnectedDeviceToList()
            handleConnectAllIsShowAndNotifyAdapter()
            viewModelActivity.scanDevice()
            scanJob()
        } else {
            stopScan()
        }
    }
    private val deviceList = arrayListOf<BleDeviceBean>()
    private val scanAdapter = ScanDeviceAdapter(deviceList, connectClick = {
        connectOrDisConnectDevice(it)
    }, lightClick = {
        if (it.isOpenLight){
            setTurnOffLight(it)
        } else {
            setTurnOnLight(it)
        }

    })

    //请求定位
    private val requestLocationPermissions =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
            val coarseLocation = result[Manifest.permission.ACCESS_COARSE_LOCATION]
            val fineLocation = result[Manifest.permission.ACCESS_FINE_LOCATION]
            if (coarseLocation == true && fineLocation == true) {
                setHasConnectDeviceCount()
                isScanning = true
            }else {
                showToast("未授权精确位置权限")
            }
        }

    //启用定位
    private val enableGPSLocation = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->

        val locationManager = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
        if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
            requestLocationPermissions.launch(
                arrayOf(
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION
                )
            )
        }else {
            showToast("位置服务未打开")
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initViews()
        scanConfig()
        (requireActivity() as MainActivity).clearAllSaveData(0)
        checkBluetoothConnectPermission()
        initObservers()
        initRecyclerView()
        getRssi()
    }

    private fun initViews(){
        setHeadTitle("蓝牙连接")
        setRightIconVisibility(View.GONE)
        isCanReceiveTemperatureAlarmInfo = false
        binding.tvConnectAll.setOnClickListener {
            stopScan()
            readToAutoConnectList.clear()
            readToAutoConnectList.addAll(deviceList.filter { !it.isConnect }.toMutableList())
            Log.i(LOG_TAG,"#$#$#$#$#$#-${readToAutoConnectList.size}")
            if (readToAutoConnectList.isNotEmpty()){
                connectOrDisConnectDevice(readToAutoConnectList[0])
            }
        }

        binding.btnNext.setOnClickListener {
            findNavController().safeNavigate(R.id.action_scan_offline_to_config_fragment)
        }

        binding.refreshLayout.setOnRefreshListener {
            Log.i(LOG_TAG,"执行下来刷新操作")
            viewLifecycleOwner.lifecycleScope.launch {
                if (isScanning){
                    isScanning = false
                }
                delay(500)
                isScanning = true
                scanJob()
            }

        }
    }

    private fun checkBluetoothConnectPermission() {
        if (isAndroid12()) {
            enableBluetoothConnect.launch(
                arrayOf(
                    Manifest.permission.BLUETOOTH_CONNECT,
                    Manifest.permission.BLUETOOTH_SCAN,
                    Manifest.permission.BLUETOOTH_ADVERTISE
                )
            )
        } else {
            enableBluetooth.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))
        }
    }

    private fun scanConfig() {
        val deviceMode = SharedPreferenceUtil.getInt(SP_DEVICE_MODE, DEVICE_MODE_NO_SELECT)
        val scanName = if (deviceMode == DEVICE_MODE_ONLINE) BLUETOOTH_NAME_ONLINE else BLUETOOTH_NAME_OFFLINE
        val scanRuleConfig = BleScanRuleConfig.Builder()
            .setDeviceName(scanName, isFuzzy = false) // 只扫描指定广播名的设备，可选
            .setScanTimeOut(3000) // 扫描超时时间，可选，默认10秒
//            .setScanSettings(scanSettings: ScanSettings)
            .build()
        BleManager.bleScanRuleConfig = scanRuleConfig
    }

    private fun getAllConnectDeviceCurrentTemperature(){
        viewLifecycleOwner.lifecycleScope.launch {
            for (item in GlobalConnectObject.getCurrentConnectDeviceList()){
                getCurrentTemperature(item)
            }
            delay(400)
            for (item in GlobalConnectObject.getCurrentConnectDeviceList()){
                getTemperatureAlarmData(item)
            }
        }
    }

    private fun scanJob(){
        scanJob = viewLifecycleOwner.lifecycleScope.launch {
            scanFlow.onEach { delay(1000) }.onCompletion {
                Log.i(LOG_TAG,"RTTT--onCompletion")
                isScanning = false
            }.collect{
                Log.i(LOG_TAG,"RTTT--${it}")
            }
        }
    }

    private fun stopJob(){
        scanJob?.cancel()
    }

    private fun getRssi(){
        viewLifecycleOwner.lifecycleScope.launch {
            IntRange(1, Int.MAX_VALUE).asFlow().onEach { delay(2000) }.collect{
                deviceList.filter { it.isConnect }.forEach { device ->
                    BleManager.readRssi(device.bleDevice,object :BleRssiCallback(){
                        override fun onRssiFailure(bleDevice: BleDevice, exception: BleException) {}

                        override fun onRssiSuccess(bleDevice: BleDevice, rssi: Int) {
                            device.rssi = rssi
                            handleConnectAllIsShowAndNotifyAdapter()
                        }

                    })
                }
            }
        }
    }

    private fun addConnectedDeviceToList(){
        deviceList.clear()
        deleteAllDisconnectDevice()
        if (GlobalConnectObject.getCurrentConnectDeviceList().isNotEmpty()){
            deviceList.addAll(GlobalConnectObject.getCurrentConnectDeviceList())
            handleConnectAllIsShowAndNotifyAdapter()
        }
    }

    private fun connectOrDisConnectDevice(scanDeviceBean: BleDeviceBean){
        showLoading()
        stopScan()
        if (scanDeviceBean.isConnect){
            viewModelActivity.disconnectDevice(scanDeviceBean)
        }else {
            viewModelActivity.connectDevice(scanDeviceBean)
        }
    }

    private fun getManufacturerData(bleDevice: BleDevice): String{
        val manufacturerData = bleDevice.scanRecord
        manufacturerData!!.toHexString(false)
        return getVersionNo(manufacturerData[13])
    }

    private fun initObservers(){
        viewLifecycleOwner.lifecycleScope.launch {

            launch {
                autoConnectFlow.collect{
                    delay(400)
                    if (readToAutoConnectList.isNotEmpty()){
                        connectOrDisConnectDevice(readToAutoConnectList[0])
                    }
                }
            }

            repeatOnLifecycle(Lifecycle.State.STARTED){

                launch {
                    GlobalAction.notifyResultFlow.collect{

                        it.bleDevice.bleDevice.scanRecord?.let { scanRecordData ->
                            //版本号小于0.5的都是没有加密的，否则都是加密的。
                            GlobalConnectObject.getDeviceFromMac(it.bleDevice.bleDevice.mac)?.isEncrypt = getVersionNumber(scanRecordData[13],true) >= 0.5
                            it.bleDevice.isEncrypt = getVersionNumber(scanRecordData[13],true) >= 0.5
                            Log.i(LOG_TAG,"广播数据---${scanRecordData.toHexString(true)}")
                            Log.i(LOG_TAG,"广播数据-版本---${getVersionNumber(scanRecordData[13],true)}")
                        }

                        //连接成功就不提示了
                        if (!it.isSuccess){
                            showToast("设备连接失败")
                        } else {
                            delay(COMMAND_DELAY_TIME_100)
                            getToken(it.bleDevice)
                        }

                    }
                }

                launch {
                    GlobalAction.startScanIfSuccessFlow.collect{
                        if (!it){
//                            showToast("开启扫描失败") //暂时去掉这个提示
                        }
                    }
                }

                launch {
                    GlobalAction.scanDeviceResultFlow.collect{ bleDevice ->
                        deviceList.add(BleDeviceBean(bleDevice = bleDevice, version = getManufacturerData(bleDevice), rssi = bleDevice.rssi, isConnect = false))
                        handleConnectAllIsShowAndNotifyAdapter()
                    }
                }

                launch {
                    GlobalAction.scanDeviceFinishFlow.collect{
                        delay(1000)
                        isScanning = false
                    }
                }

                launch {
                    GlobalAction.mtuSetFailureFlow.collect{
                        dismissLoading()
                    }
                }

                launch {
                    GlobalAction.mtuSetSuccessFlow.collect{
                            delay(COMMAND_DELAY_TIME_100)
                        Log.i(LOG_TAG,"MTU Success ${it.mac}")
                            viewModelActivity.turnOnIndicate(it)

                    }
                }

                launch {
                    GlobalAction.connectFailureFlow.collect{
                        showToast("设备连接失败")
                        dismissLoading()
                    }
                }

                launch {
                    GlobalAction.disConnectFlow.collect{ disConnectDevice ->
                        dismissLoading()
                        setHasConnectDeviceCount()
                        val disconnectDeviceInList = deviceList.find { it.bleDevice.mac ==  disConnectDevice.mac}
                        disconnectDeviceInList?.let {
                            it.isConnect = false
                        }
                        isScanning = true
                    }
                }
            }
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    private fun handleConnectAllIsShowAndNotifyAdapter(){
        binding.tvConnectAll.visibility = if (deviceList.any { !it.isConnect }) View.VISIBLE else View.GONE
        scanAdapter.notifyDataSetChanged()
    }

    override fun whenConnectSuccess(bleDeviceBean: BleDeviceBean) {
        super.whenConnectSuccess(bleDeviceBean)
        viewLifecycleOwner.lifecycleScope.launch {
            delay(100)
            viewModelActivity.setMtu(bleDeviceBean.bleDevice,200)
            bleDeviceBean.isConnect = true
            GlobalConnectObject.addDeviceToConnectList(bleDeviceBean)
            handleConnectAllIsShowAndNotifyAdapter()
            setHasConnectDeviceCount()
        }
    }

    override fun whenReceiveCommand(bleDevice: BleDeviceBean,command: String, dataByteArray: ByteArray) {
        super.whenReceiveCommand(bleDevice, command, dataByteArray)
        when (command) {
            COMMAND_TOKEN_UPWARD -> {
                SharedPreferenceUtil.putString(bleDevice.bleDevice.mac, dataByteArray.toHexString(false))
                getVersion(bleDevice)
            }

            COMMAND_FIRMWARE_VERSION_UPWARD -> {
                val softVersion = getVersionNoOffline(dataByteArray[0])
                val hardVersion = getVersionNoOffline(dataByteArray[1], false)
                GlobalConnectObject.setHardAndSoftVersion(bleDevice.bleDevice, softVersion, hardVersion)
                Log.i(LOG_TAG, "获取到的版本号为：固件-${softVersion}---硬件：${hardVersion}")
                getCurrentTemperature(bleDevice)
            }

            COMMAND_TEMPERATURE_ALARM_GET_UPWARD -> {
                (requireActivity() as MainActivity).saveData(
                    0,
                    bleDevice.bleDevice,
                    COMMAND_TEMPERATURE_ALARM_SET_DOWNLOAD,
                    dataByteArray.toHexString(false)
                )
                if (readToAutoConnectList.isNotEmpty()) {
                    readToAutoConnectList.removeAt(0)
                    autoConnectFlow.tryEmit(true)
                }
                binding.btnNext.visibility = View.VISIBLE
                dismissLoading()
            }

            COMMAND_TEMPERATURE_GET_OFFLINE_UPWARD -> {
                deviceList.find { it.bleDevice == bleDevice.bleDevice }?.let {
                    it.isOpenLight = dataByteArray[1].toInt() != 0
                }
                getTemperatureAlarmData(bleDevice)

            }

            COMMAND_TEMPERATURE_ALARM_SET_UPWARD -> {
                if (!isCanReceiveTemperatureAlarmInfo) return
                dismissLoading()
                if (dataByteArray[dataByteArray.size - 1].toInt() == SuccessFailEnum.SUCCESS.value) {
                    deviceList.find { bleDeviceBean -> bleDeviceBean.bleDevice == bleDevice.bleDevice }?.let {
                        it.isOpenLight = !it.isOpenLight
                        handleConnectAllIsShowAndNotifyAdapter()
                    }
                }
            }
        }
    }

    override fun initOnCreateView() {
        super.initOnCreateView()
    }

    private fun setHasConnectDeviceCount(){
        val count = viewModelActivity.getAllConnectDevices().size
        binding.tvConnectCount.text = "$count"
        binding.btnNext.visibility = if (count > 0) View.VISIBLE else View.GONE
    }



    private fun initRecyclerView(){
        binding.rvScanResult.apply {
            adapter = scanAdapter
            layoutManager = LinearLayoutManager(requireContext())
            addItemDecoration(DividerItemDecoration(requireContext(),DividerItemDecoration.VERTICAL))
        }
    }

    override fun getViewBinding(inflater: LayoutInflater, container: ViewGroup): FragmentScanOfflineBinding {
        return FragmentScanOfflineBinding.inflate(inflater,container,true)
    }

    private fun getToken(bleDevice: BleDeviceBean){
        getCommandData(bleDevice,COMMAND_TOKEN_DOWNWARD,timestamp())
    }

    private fun getVersion(bleDevice: BleDeviceBean){
        getCommandData(bleDevice, COMMAND_FIRMWARE_VERSION_DOWNWARD)
    }

    private fun getTemperatureAlarmData(bleDevice: BleDeviceBean){
        getCommandData(bleDevice, COMMAND_TEMPERATURE_ALARM_GET_DOWNWARD)
    }

    private fun getCurrentTemperature(bleDevice: BleDeviceBean){
        getCommandData(bleDevice, COMMAND_TEMPERATURE_GET_OFFLINE_DOWNWARD, intToByteHexString(OFFLINE_DEVICE_LEFT))
    }

    private fun setTurnOnLight(bleDevice: BleDeviceBean){
        isCanReceiveTemperatureAlarmInfo = true
        val commandData = byteArrayOf(1.toByte(),(-20).toByte(),0.toByte(),89.toByte()).toHexString(false)
        setCommandData(bleDevice, COMMAND_TEMPERATURE_ALARM_SET_DOWNLOAD,commandData)
    }

    private fun setTurnOffLight(bleDevice: BleDeviceBean){
        isCanReceiveTemperatureAlarmInfo = true
        val commandData = byteArrayOf(90.toByte(),(-20).toByte(),0.toByte(),89.toByte()).toHexString(false)
        setCommandData(bleDevice, COMMAND_TEMPERATURE_ALARM_SET_DOWNLOAD,commandData)
    }



    private fun stopScan(){
        Log.i(LOG_TAG,"停止扫描")
        stopJob()
        BleManager.cancelScan()
    }

    override fun bluetoothClose() {
        if (BleScan.isScanning) {
            stopScan()
        }
    }

    override fun locationClose() {
        if (BleScan.isScanning) {
            stopScan()
        }
    }

    override fun onResume() {
        super.onResume()
        setHasConnectDeviceCount()
        getAllConnectDeviceCurrentTemperature()
    }

    override fun onDestroyView() {
        super.onDestroyView()
        stopScan()
        Log.i(LOG_TAG,"ScanFragment onDestroyView")
        GlobalConnectObject.getCurrentConnectDeviceList().forEach {
            it.isOpenLight = false
        }
        (requireActivity() as MainActivity).restoreData(0)
    }
}